diff --git a/keyserver/flow-typed/npm/frog_v0.18.x.js b/keyserver/flow-typed/npm/frog_v0.18.x.js index 7a0ca4770..fc702ebc8 100644 --- a/keyserver/flow-typed/npm/frog_v0.18.x.js +++ b/keyserver/flow-typed/npm/frog_v0.18.x.js @@ -1,45 +1,45 @@ // flow-typed signature: 8b45e30d3c592dc3c877fcba96c687fb // flow-typed version: <>/frog_v0.18.x/flow_v0.202.1 declare module 'frog' { import type { Fetch, HonoRequest } from '@hono/node-server'; declare type FrameResponse = { +image: React$Node, +intents: $ReadOnlyArray, ... }; declare export var Button: { Link: React$ComponentType<{ +children: React$Node, +href: string, ... }>, ... }; declare opaque type FrogResponse; declare opaque type FrogRequest; declare type FrameContext = { +res: (response: FrameResponse) => FrogResponse, +req: HonoRequest, ... }; declare type FrogOptions = { +title: string, ... }; declare export class Frog { constructor(options?: FrogOptions): this; frame( route: string, - callback: (c: FrameContext) => FrogResponse, + callback: (c: FrameContext) => Promise | FrogResponse, ): void; fetch: Fetch, } } diff --git a/keyserver/src/frog/frog.js b/keyserver/src/frog/frog.js index 715addf42..9adacfcf0 100644 --- a/keyserver/src/frog/frog.js +++ b/keyserver/src/frog/frog.js @@ -1,45 +1,83 @@ // @flow /** @jsxImportSource hono/jsx */ /* eslint-disable react/react-in-jsx-scope */ import { serve } from '@hono/node-server'; import { Button, Frog } from 'frog'; import { inviteLinkURL } from 'lib/facts/links.js'; +import { ignorePromiseRejections } from 'lib/utils/promises.js'; + +import { neynarClient } from '../utils/fc-cache.js'; +import { redisCache } from '../utils/redis-cache.js'; function startFrogHonoServer() { const frogApp = new Frog({ title: 'Comm' }); - frogApp.frame('/:inviteLink', c => { - const { inviteLink } = c.req.param(); + frogApp.frame('/:inviteLink/:channelID', async c => { + const { inviteLink, channelID } = c.req.param(); let buttonLink = 'https://comm.app'; const inviteLinkURLPrefix = inviteLinkURL(''); if (inviteLink.startsWith(inviteLinkURLPrefix)) { buttonLink = inviteLink; } + let channelInfo = await redisCache.getChannelInfo(channelID); + if (!channelInfo) { + channelInfo = await neynarClient?.fetchFarcasterChannelByID(channelID); + + if (channelInfo) { + ignorePromiseRejections( + redisCache.setChannelInfo(channelID, channelInfo), + ); + } + } + + let header_image_url = + 'https://warpcast.com/~/images/DefaultChannelCoverImage.png'; + if (channelInfo?.header_image_url) { + header_image_url = channelInfo.header_image_url; + } + return c.res({ image: ( -
- Hello World! +
+ frame background
), intents: [ Join chat , ], }); }); serve({ fetch: frogApp.fetch, port: parseInt(process.env.FROG_PORT, 10) || 3001, }); } export { startFrogHonoServer }; diff --git a/lib/types/farcaster-types.js b/lib/types/farcaster-types.js index b45c76b48..12c0c764c 100644 --- a/lib/types/farcaster-types.js +++ b/lib/types/farcaster-types.js @@ -1,91 +1,92 @@ // @flow // This is a message that the rendered webpage // (landing/connect-farcaster.react.js) uses to communicate back // to the React Native WebView that is rendering it // (native/components/farcaster-web-view.react.js) export type FarcasterWebViewMessage = | { +type: 'farcaster_url', +url: string, } | { +type: 'farcaster_data', +fid: string, }; export type NeynarUser = { +fid: number, +username: string, +pfp_url: string, ... }; export type NeynarUserWithViewerContext = $ReadOnly<{ ...NeynarUser, +viewerContext: { +following: boolean, }, ... }>; export type NeynarChannel = { +id: string, +name: string, +follower_count: number, +lead: { +fid: number, ... }, +image_url: string, + +header_image_url?: string, +description: string, ... }; export type NeynarCast = { +hash: string, +thread_hash: string, +text: string, +author: NeynarUser, ... }; export type NeynarWebhookCastAuthor = { +object: 'user', +fid: number, +custody_address: string, +username: string, +display_name: string, +pfp_url: string, ... }; export type NeynarWebhookCastCreatedData = { +object: 'cast', +hash: string, +thread_hash: string, +text: string, +channel?: ?NeynarWebhookChannel, +parent_hash?: ?string, +author: NeynarWebhookCastAuthor, ... }; export type NeynarWebhookChannel = { +id: string, +name: string, +image_url: string, ... }; export type NeynarWebhookCastCreatedEvent = { +created_at: number, +type: 'cast.created', +data: NeynarWebhookCastCreatedData, ... }; export type NeynarPostCastResponse = { +success: boolean, ... };